﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using NHibernate.Criterion;

using ProjectBase.Core;

namespace $safeprojectname$
{
    public static partial class DaoExtensions
    {
        #region IN

        public static IList<ICriterion> AddIn<TFilter, TValue>(this IList<ICriterion> restrictions, TFilter filter, Expression<Func<TFilter, IList<TValue?>>> expr)
            where TFilter : Core.IFilter
            where TValue : struct
        {
            MemberExpression body;
            switch (expr.Body.NodeType)
            {
                case ExpressionType.MemberAccess: // e.g. entity.User
                    body = expr.Body as MemberExpression;
                    break;

                default:
                    throw new NotSupportedException(
                        "Provided 'Expression<Func<TFilter, IList<TValue?>>> expr' parameter must be of a 'ExpressionType.MemberAccess'. ");
            }

            var compiled = GetCompiled(expr);

            var fullList = compiled(filter);

            if (fullList.IsEmpty())
            {
                return restrictions;
            }

            var list = fullList.Distinct().ToList();

            var name = body.Member.Name;

            // collection names end with 's' on the Filters
            if (name.IsEqual("IDColl"))
            {
                name = "ID";
            }
            else if (name.EndsWith("Coll", StringComparison.InvariantCulture))
            {
                name = name.Substring(0, name.Length - 4);
            }

            var findNull = list.Contains(null);

            if (findNull)
            {
                list.Remove(null);
                if (list.IsNotEmpty())
                {
                    // IS NULL or IN
                    restrictions.Add
                        (
                            new OrExpression
                                (new NullExpression(name)
                                , new InExpression(name, list.Cast<object>().ToArray()))
                        );
                    return restrictions;
                }
                // just IS NULL
                restrictions.Add(new NullExpression(name));
                return restrictions;
            }

            // just IN
            restrictions.Add
            (
                new InExpression(name, list.Cast<object>().ToArray())
            );

            return restrictions;
        }

        #endregion IN

        #region CompiledCache

        private static Func<TFilter, TResult> GetCompiled<TFilter, TResult>(Expression<Func<TFilter, TResult>> expr)
            where TFilter : Core.IFilter
        {
            var key = typeof(TFilter).Name + "|" + expr.ToString();
            object obj;
            if (!Funcs.TryGetValue(key, out obj))
            {
                lock (Locker)
                {
                    obj = expr.Compile();
                    Funcs[key] = obj;
                }
            }
            return obj as Func<TFilter, TResult>;
        }

        private static object Locker = new object();
        public static IDictionary<string, object> Funcs = new Dictionary<string, object>();

        #endregion CompiledCache
    }
}